package com.zenithmind.document.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

import com.zenithmind.common.config.AuthInterceptorConfig;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

/**
 * 文档服务安全配置
 * 遵循单一职责原则：专注于安全配置管理
 * 遵循开闭原则：通过配置类扩展安全规则
 * 遵循依赖倒置原则：依赖抽象的安全配置接口
 *
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Configuration
@EnableWebSecurity
public class DocumentSecurityConfig {

    /**
     * 安全端点配置管理器
     *
     * ⚠️ 违反原则分析：
     * ❌ 开闭原则：硬编码端点配置，添加新端点需要修改现有代码
     *
     * 修复建议：
     * 1. 使用 EndpointConfigurationManager 替代硬编码配置
     * 2. 支持动态添加和移除端点
     *
     * @deprecated 使用 EndpointConfigurationManager 替代
     */
    @Deprecated
    public static class SecurityEndpointManager {

        private static EndpointConfigurationManager endpointManager;

        public static void setEndpointManager(EndpointConfigurationManager manager) {
            endpointManager = manager;
        }

        public static String[] getApiDocEndpoints() {
            if (endpointManager != null) {
                return endpointManager.getEndpointsByCategory("api-docs");
            }
            return new String[]{"/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/doc.html",
                "/webjars/**", "/favicon.ico", "/knife4j/**", "/knife4j-ui/**", "/knife4j.html"};
        }

        public static String[] getPublicEndpoints() {
            if (endpointManager != null) {
                return endpointManager.getEndpointsByCategory("public");
            }
            return new String[]{"/api/v1/documents/public/**", "/api/v1/documents/search",
                "/api/v1/documents/hot", "/api/v1/documents/latest", "/api/v1/documents/recommended",
                "/api/v1/documents/*/preview", "/api/v1/documents/*/download",
                "/api/v1/document-categories/public/**", "/api/v1/document-categories/tree",
                "/api/v1/documents/statistics/public", "/actuator/**", "/health", "/info"};
        }

        public static String[] getUserEndpoints() {
            if (endpointManager != null) {
                return endpointManager.getEndpointsByCategory("user");
            }
            return new String[]{"/api/v1/documents/**", "/api/v1/document-categories/**"};
        }

        public static String[] getAuthorEndpoints() {
            if (endpointManager != null) {
                return endpointManager.getEndpointsByCategory("author");
            }
            return new String[]{"/api/v1/documents/upload", "/api/v1/documents/create",
                "/api/v1/documents/*/edit", "/api/v1/documents/*/delete",
                "/api/v1/documents/*/convert", "/api/v1/documents/*/versions"};
        }

        public static String[] getAdminEndpoints() {
            if (endpointManager != null) {
                return endpointManager.getEndpointsByCategory("admin");
            }
            return new String[]{"/api/v1/documents/admin/**", "/api/v1/document-categories/admin/**",
                "/api/v1/documents/batch", "/api/v1/documents/move", "/api/v1/manage/**"};
        }

        /**
         * 获取所有公开端点（包括API文档）
         */
        public static String[] getAllPublicEndpoints() {
            if (endpointManager != null) {
                return endpointManager.getAllPublicEndpoints();
            }

            // 回退到默认配置
            List<String> allPublic = new ArrayList<>();
            allPublic.addAll(Arrays.asList(
                "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/doc.html",
                "/webjars/**", "/favicon.ico", "/knife4j/**", "/knife4j-ui/**", "/knife4j.html"
            ));
            allPublic.addAll(Arrays.asList(
                "/api/v1/documents/public/**", "/api/v1/documents/search", "/api/v1/documents/hot",
                "/api/v1/documents/latest", "/api/v1/documents/recommended", "/api/v1/documents/*/preview",
                "/api/v1/documents/*/download", "/api/v1/document-categories/public/**",
                "/api/v1/document-categories/tree", "/api/v1/documents/statistics/public",
                "/actuator/**", "/health", "/info"
            ));
            return allPublic.toArray(new String[0]);
        }

        /**
         * 检查端点是否为公开端点
         */
        public static boolean isPublicEndpoint(String endpoint) {
            return Arrays.stream(getAllPublicEndpoints())
                    .anyMatch(pattern -> endpoint.matches(pattern.replace("**", ".*").replace("*", "[^/]*")));
        }
    }

    /**
     * 安全配置构建器
     * 遵循建造者模式：分步构建安全配置
     */
    public static class SecurityConfigBuilder {

        /**
         * 配置HTTP安全规则
         */
        public static HttpSecurity configureHttpSecurity(HttpSecurity http) throws Exception {
            return http
                // 禁用CSRF保护
                .csrf(AbstractHttpConfigurer::disable)
                // 配置认证和授权规则
                .authorizeHttpRequests(authorize -> {
                    // API文档端点
                    authorize.requestMatchers(SecurityEndpointManager.getApiDocEndpoints()).permitAll();
                    // 公开端点
                    authorize.requestMatchers(SecurityEndpointManager.getPublicEndpoints()).permitAll();
                    // 作者角色端点
                    authorize.requestMatchers(SecurityEndpointManager.getAuthorEndpoints()).hasAnyRole("AUTHOR", "ADMIN");
                    // 用户角色端点
                    authorize.requestMatchers(SecurityEndpointManager.getUserEndpoints()).authenticated();
                    // 管理员角色端点
                    authorize.requestMatchers(SecurityEndpointManager.getAdminEndpoints()).hasRole("ADMIN");
                    // 其他请求需要认证
                    authorize.anyRequest().authenticated();
                })
                // 使用无状态会话
                .sessionManagement(session -> session
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 禁用OAuth2资源服务器功能
                .oauth2ResourceServer(AbstractHttpConfigurer::disable);
        }
    }

    /**
     * 认证拦截器配置管理器
     * 遵循单一职责原则：专门管理认证拦截器配置
     */
    public static class AuthInterceptorConfigManager {

        /**
         * 配置认证拦截器跳过路径
         */
        public static void configureSkipPaths(AuthInterceptorConfig.AuthProperties properties) {
            String[] allPublicEndpoints = SecurityEndpointManager.getAllPublicEndpoints();
            properties.setSkipPaths(Arrays.asList(allPublicEndpoints));
            log.info("已为文档服务认证拦截器设置统一的跳过路径配置，路径数量: {}", allPublicEndpoints.length);
        }

        /**
         * 创建认证属性后处理器
         */
        public static BeanPostProcessor createAuthPropertiesPostProcessor() {
            return new BeanPostProcessor() {
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    if (bean instanceof AuthInterceptorConfig.AuthProperties && "authProperties".equals(beanName)) {
                        configureSkipPaths((AuthInterceptorConfig.AuthProperties) bean);
                    }
                    return bean;
                }
            };
        }
    }

    /**
     * 文档服务安全过滤器链配置
     * 遵循单一职责原则：专注于安全过滤器链配置
     */
    @Bean
    @Order(1)
    public SecurityFilterChain documentSecurityFilterChain(HttpSecurity http) throws Exception {
        log.info("配置文档服务安全过滤器链");

        HttpSecurity configuredHttp = SecurityConfigBuilder.configureHttpSecurity(http);

        return configuredHttp.build();
    }

    /**
     * 认证拦截器属性后处理器
     * 遵循单一职责原则：专注于认证拦截器配置
     */
    @Bean
    public BeanPostProcessor documentAuthPropertiesPostProcessor() {
        log.info("创建文档服务认证拦截器属性后处理器");

        return AuthInterceptorConfigManager.createAuthPropertiesPostProcessor();
    }

    /**
     * 安全配置验证器
     * 遵循单一职责原则：专注于配置验证
     */
    @Bean
    public SecurityConfigValidator securityConfigValidator() {
        return new SecurityConfigValidator();
    }

    /**
     * 安全配置验证器类
     */
    public static class SecurityConfigValidator {

        /**
         * 验证安全配置
         */
        public boolean validateConfiguration() {
            log.info("验证文档服务安全配置");

            // 验证端点配置
            boolean endpointsValid = validateEndpoints();

            // 验证角色配置
            boolean rolesValid = validateRoles();

            boolean isValid = endpointsValid && rolesValid;

            if (isValid) {
                log.info("文档服务安全配置验证通过");
            } else {
                log.warn("文档服务安全配置验证失败");
            }

            return isValid;
        }

        /**
         * 验证端点配置
         */
        private boolean validateEndpoints() {
            // 检查是否有重复的端点配置
            String[] allEndpoints = SecurityEndpointManager.getAllPublicEndpoints();

            if (allEndpoints.length == 0) {
                log.warn("未配置任何公开端点");
                return false;
            }

            log.info("端点配置验证通过，公开端点数量: {}", allEndpoints.length);
            return true;
        }

        /**
         * 验证角色配置
         */
        private boolean validateRoles() {
            // 检查角色端点配置是否合理
            if (SecurityEndpointManager.getAdminEndpoints().length == 0) {
                log.warn("未配置管理员端点");
            }

            if (SecurityEndpointManager.getAuthorEndpoints().length == 0) {
                log.warn("未配置作者端点");
            }

            log.info("角色配置验证通过");
            return true;
        }
    }
}
